package com.lin.demo.interceptor;

import com.lin.demo.mapper.SysLogMapper;
import com.lin.demo.po.SysLog;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.Map;
import java.util.Optional;

/**
 * @Author zimingl
 * @Date 2023/3/31 18:48
 * @Description: 日志收集
 */

@Component
@Slf4j
public class LogInterceptor implements HandlerInterceptor{
    public static final ThreadLocal<String> REQ_BODY = new ThreadLocal<>();

    public static final ThreadLocal<String> REP_BODY = new ThreadLocal<>();

    public static final ThreadLocal<Long> COST_TIME = new ThreadLocal<>();

    @Resource
    private SysLogMapper sysLogMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        COST_TIME.set(System.currentTimeMillis());
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        String req = null;
        try {
            String requestURI = request.getRequestURI();
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            ApiOperation apiOperation = handlerMethod.getMethodAnnotation(ApiOperation.class);
            Method method = handlerMethod.getMethod();
            SysLog sysLog = new SysLog();
            sysLog.setCostTime(System.currentTimeMillis() - COST_TIME.get());
            sysLog.setRequestParam(REQ_BODY.get());
            if (REQ_BODY.get() == null) {
                sysLog.setRequestParam(getRequestParam(request));
            }
            sysLog.setResourceType(Optional.ofNullable(apiOperation).map(ApiOperation::notes).orElse(null));
            sysLog.setRequestType(request.getMethod().toUpperCase());
            sysLog.setRequestUrl(requestURI);
            sysLog.setMethod(method.getDeclaringClass().getName() + "." + method.getName() + "()");
            sysLog.setLogContent(Optional.ofNullable(apiOperation).map(ApiOperation::value).orElse(null));
            sysLog.setProductId(getProductParam(request));
            sysLog.setVersionId(getVersionParam(request));
            sysLog.setResponseCode(response.getStatus());
            sysLog.setResponseParam(getResponseParam(response));
            sysLogMapper.insert(sysLog);
        } catch (Exception e) {
            log.error("logInterceptor, req:{}, rep:{}", req, REP_BODY.get());
        } finally {
            REP_BODY.remove();
            REQ_BODY.remove();
            COST_TIME.remove();
        }
    }

    private String getResponseParam(HttpServletResponse response) {
        return "";
    }

    private String getRequestParam(HttpServletRequest request) {
        StringBuilder strBuffer = new StringBuilder();
        for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
            strBuffer.append(entry.getKey()).append(": ");
            for (int i = 0; i < entry.getValue().length; i++) {
                if (i == entry.getValue().length - 1) {
                    strBuffer.append(entry.getValue()[i]);
                    continue;
                }
                strBuffer.append(entry.getValue()[i]).append(",");
            }
            strBuffer.append("; ");
        }
        return strBuffer.toString();
    }

    private String getProductParam(HttpServletRequest request) {
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            // 获取产品
            if (name.contains("product")) {
                return request.getHeader(name);
            }
        }
        return null;
    }

    private String getVersionParam(HttpServletRequest request) {
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            // 获取版本
            if (name.contains("version")) {
                return request.getHeader(name);
            }
        }
        return null;
    }
}
